// 读取项目根路径
const path = require('path')

// 引入插件构造函数
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CSSMinimizerPlugin = require('css-minimizer-webpack-plugin')
const TerserPlugin = require('terser-webpack-plugin')
const toml = require('toml');
const yaml = require('yaml');
const json5 = require('json5');

const resolvePath = (dicName) => path.resolve(__dirname, dicName)

module.exports = {
  // 打包的模式，生产模式 production | 开发模式 development | none
  mode: 'development',
  // 多入口配置
  entry: {
    index: './src/index.js',
    another: './src/another-module.js'
  },

  output: {
    // 默认输出文件名称及文件路径，配置多个输出文件
    // 输出文件名设置为根据文件内容 hash 值命名，可避免浏览器缓存不能及时更新资源
    filename: 'scripts/[name].[contenthash].js',
    path: resolvePath('./dist'),
    // 清理 dist 文件夹
    clean: true,
    // 配置 assets 静态资源文件输入路径和输出文件名称 
    // 1. 输出路径 images 2. 文件名[contentHash] 表示文件内容 hash 值 3. [ext]表示文件扩展名
    assetModuleFilename: 'images/[contenthash][ext]',
    publicPath: 'http://localhost:8080/'
  },

  // 配置 source-map
  devtool: 'inline-source-map',

  // 配置 webpack-dev-server
  devServer: {
    // 静态资源目录
    static: './dist',
  },

  // 配置 loader 规则
  module: {
    rules: [{
      // 解析 js 文件，将 ES6 代码转换成 ES5
      test: /\.js$/,
      exclude: /node_modules/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-env'],
          plugins: [['@babel/plugin-transform-runtime']]
        }
      }
    }, {
      // 正则判断加载的资源文件类型
      test: /\.png$/,
      // asset/resource 类型会打包出一个文件并且导入该资源得到的是资源的 URL
      // 比如 http://localhost:8080/images/img1.png
      type: 'asset/resource',
      // 效果同 assetModuleFilename，但是优先级更高，打包时会先以这个为准
      generator: {
        filename: 'images/[name][ext]'
      }
    }, {
      test: /\.svg$/,
      // asset/resource 类型导入资源得到的是该资源的 DataURL (base64 格式的 src)
      // 比如 ...
      type: 'asset/inline'
    }, {
      test: /\.txt$/,
      // asset/source 类型导入资源得到的是该资源的源代码
      type: 'asset/source'
    }, {
      test: /\.jpg$/,
      // asset/source 类型会在导出文件和导出 DataURL 之间自动选择
      type: 'asset',
      // 配置资源大小条件，不超过 1M 就转成 base64
      // parser: {
      //   dataUrlCondition: {
      //     maxSize: 8 * 1024
      //   }
      // }
    }, {
      test: /\.(css|less)$/,
      // use: ['style-loader', 'css-loader', 'less-loader']
      // 使用 mini-css-extract-plugin 插件之后
      use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader']
    }, {
      // 处理字体文件
      test: /\.(woff|woff2|eot|ttf|otf)$/,
      type: 'asset/resource'
    }, {
      // 处理 csv/tsv 文件
      test: /\.(csv|tsv)$/,
      use: 'csv-loader'
    }, {
      // 处理 xml 文件
      test: /\.(xml)$/,
      use: 'xml-loader'
    }, {
      // 处理 toml 文件，必须要 parser 解析器
      test: /\.toml$/,
      type: 'json',
      parser: {
        parse: toml.parse
      }
    }, {
      // 处理 yaml 文件，必须要 parser 解析器
      test: /\.yaml$/,
      type: 'json',
      parser: {
        parse: yaml.parse
      }
    }, {
      // 处理 json5 文件，必须要 parser 解析器
      test: /\.json5$/,
      type: 'json',
      parser: {
        parse: json5.parse
      }
    }]
  },

  // 插件配置
  plugins: [
    new HtmlWebpackPlugin({
      // 输出文件的模板
      // template: './index.html',
      // 输出文件名称，默认 bundle.js
      filename: 'app.html',
      // inject: true | 'head' | 'body' | false  ,注入所有的资源到特定的 template 或者 templateContent 中，如果设置为 true 或者 body，所有的 javascript 资源将被放置到 body 元素的底部，'head' 将放置到 head 元素中。
      inject: 'body',
    }),
    // 实例化抽离压缩 css 的插件
    new MiniCssExtractPlugin({
      // 指定打包生成的 css 文件的路径和名称
      filename: 'style/[contenthash].css'
    })
  ],

  // 优化配置
  optimization: {
    minimizer: [
      new CSSMinimizerPlugin(),
      // webpack 开箱即用的 js 代码压缩插件
      new TerserPlugin()
    ],

    // 配置分离代码
    splitChunks: {
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all'
        }
      }
    }
  }
}